#include <string>
#include "EngineApplication.h"
#include "EnginePointer.h"
#include "SettingsManager.h"
#include "EngineLog.h"
#include "EngineProfileSample.h"
#include "ISystemConfiguration.h"

using namespace std;

HRESULT EngineApplication::Run(EnginePointer<ISystemConfiguration>& configuration, int argc, char* argv[])
{
	HRESULT hr;
	EnginePointer<EngineEntityCollection> entities;
	EnginePointer<SettingsManager> settings;
	EnginePointer<Engine> engine;

	hr = InitializeLog();
	if (FAILED(hr)) goto END;

	hr = ReadSettings();
	if (FAILED(hr)) goto END;

	hr = ParseSettings(argc, argv);
	if (FAILED(hr)) goto END;

	hr = ReadEntities(&entities);
	if (FAILED(hr)) goto END;

	hr = InitializeEngine(&engine, configuration);
	if (FAILED(hr)) goto END;

	hr = AddEntities(engine, entities);
	if (FAILED(hr)) goto END;

	hr = RunEngine(engine);
	if (FAILED(hr)) goto END;

END:
	EngineProfileSample::Output();

	return hr;
}

HRESULT EngineApplication::InitializeLog()
{
	EngineProfileSample::outputHandler = &profileLogHandler;

	if (EngineLog::Get().Init())
		return S_OK;
	else
		return E_FAIL;
}

HRESULT EngineApplication::ReadSettings()
{
	settings = new SettingsManager(new XmlSerializer("settings.xml"));
	settings->ReadSettings();

	return S_OK;
}

HRESULT EngineApplication::ParseSettings(int argc, char* argv[])
{
	UNREFERENCED_PARAMETER(argc);
	UNREFERENCED_PARAMETER(argv);

	//parse command-line arguments
	//skip the first argument, which is always the program name
	/*if(argc>1)
	{
		for(int i=1;i<argc;i++)
		{
			settings->ParseSetting(string(argv[i]));
		}
	}*/

	return S_OK;
}

HRESULT EngineApplication::ReadEntities(EnginePointer<EngineEntityCollection>* entities)
{
	char* sceneLocation = settings->GetVariableAsString("Scene");

	if (sceneLocation == NULL)
	{
		sceneLocation = "scene.xml";
	}

	EnginePointer<ISerializer> serializer = new XmlSerializer(sceneLocation);
	EnginePointer<ISerializerReadContext> readContext = serializer;

	serializer->BeginDeserialization();
	*entities = EngineEntityCollection::Deserialize(readContext);
	serializer->EndDeserialization();

	return S_OK;
}

HRESULT EngineApplication::InitializeEngine(EnginePointer<Engine>* engine, EnginePointer<ISystemConfiguration>& configuration)
{
	*engine = new Engine(configuration, settings);
	return (*engine)->Initialize();
}

HRESULT EngineApplication::AddEntities(EnginePointer<Engine>& engine, EnginePointer<EngineEntityCollection>& entities)
{
	HRESULT hr = S_OK;
	for (EngineEntityCollection::iterator it = entities->begin(); it != entities->end() && SUCCEEDED(hr); it++)
	{
		hr = engine->AddEntity((*it));
	}

	return hr;
}

HRESULT EngineApplication::RunEngine(EnginePointer<Engine>& engine)
{
	engine->Run();

	return S_OK;
}